
/**
 * -----------------------------------------------------------
 * 数量增减组件
 * -----------------------------------------------------------
	<div class="amount">
		<div class="price"> 单价: <span class="value">20</span> </div>
		<div class="quantity-box">
			<button class="minus">-</button>
			<input type="text" name="quantity" value="3" />
			<button class="plus">+</button>
		</div>
		<div class="subtotal"> 小计: <span class="value">60</span> </div>
	</div>
 * -----------------------------------------------------------
 * // 初始化绑定事件
 * // function=onQuantityChanged, this=input[name=quantity]
 * $(document.body).quantity(function(newValue, oldValue) {
 *     // do something
 * });
 * -----------------------------------------------------------
 * // 重新计算小计金额(subtotal)
 * $(document.body).quantity("calculate");
 * -----------------------------------------------------------
 * author: 赵卉华 / 2018-07-11
 * -----------------------------------------------------------
 */
+function() {

	$.fn.quantity = function(type, options) {
		if (type == undefined) {
			type = "init"; options = undefined;
		} else if ($.isFunction(type)) {
			options = { onQuantityChanged:type }; type = "init";
		} else if ($.isPlainObject(type)) {
			options = type; type = "init";
		} else if (type == "init" && $.isFunction(options)) {
			options = { onQuantityChanged:options };
		}
		var o = $.extend(true, {}, zv.options, options);
		var method = zv.methods[type];
		if (!method) {
			$.log.error("$.fn.quantity.defaults.methods." + type + " not found!");
			return this;
		}
		if ($.isFunction(method)) { method = { type:"setter", fn:method }; }
		if (method.type == "getter") {
			return method.fn.call(this.get(0), o);
		} else {
			return this.each(function() {
				method.fn.call(this, o);
			});
		}
	};
	// 绑定事件
	var bindEvent = function(me, o) {
		me.find(o.selectors.input).zchanged(function(newValue, oldValue) {
			var input = $(this);
			if (o.isEffectiveValue(newValue)) {
				calculateSubTotalAmount(input, newValue, oldValue, o);
				if ($.isFunction(o.onQuantityChanged)) {
					o.onQuantityChanged.call(input.get(0), newValue, oldValue, o);
				}
			}
		}).blur(function() {
			var input = $(this);
			var value = input.val();
			if (!o.isEffectiveValue(value)) {
				input.val(o.toEffectiveValue(value)).zchanged("check");
			}
		});
		me.find(o.selectors.minus).click(function() {
			changeQuantity.call(this, -1, o);
		});
		me.find(o.selectors.plus).click(function() {
			changeQuantity.call(this, +1, o);
		});
	};
	// 数量增减计算金额
	var changeQuantity = function(n, o) { // n = 1 or -1
		var me = $(this);
		var box = me.closest(o.selectors.row);
		var input = box.find(o.selectors.input);
		var value = input.val();
		var newValue = (value || 1) * 1 + n;
		if (newValue <= 0) { newValue = 1; }
		if (value == newValue) return;
		input.val(newValue).zchanged("check");
	};
	var calculateSubTotalAmount = function(input, newValue, oldValue, o) {
		if (newValue <= 0) { newValue = 1; }
		var box = input.closest(o.selectors.row);
		var price = box.find(o.selectors.price).text().replace(/[^\.\d]/g,"") * 1;
		if (price) {
			var $subtotal = box.find(o.selectors.subtotal);
			var format = $subtotal.zoptions().format || o.format;
			var text = price * newValue;
			if (format) { text = $.zhh.format(format, { value:text }); }
			$subtotal.text(text);
		}
	};
	var doExecCalculate = function(box, o) {
		var input = box.find(o.selectors.input);
		var value = input.val();
		var newValue = (value || 1) * 1;
		if (newValue <= 0) { newValue = 1; }
		calculateSubTotalAmount(input, newValue, value, o);
	};
	var zv = $.fn.quantity.defaults = {
		options: {
			format: null, // 数字格式, 如: &yen;{value}元
			selectors: { 
				row:".amount", 
				price:".price .value", 
				subtotal:".subtotal .value",
				input:".quantity-box input[name=quantity]",
				minus:".quantity-box .minus",
				plus:".quantity-box .plus"
			},
			isEffectiveValue: function(text) {
				if (!$.dt.isNumeric(text)) { return false; }
				var value = parseFloat(text);
				return value > 0 && parseInt(value) === value;
			},
			toEffectiveValue: function(text) {
				return Math.max(1,  parseInt(text));
			},
			onQuantityChanged: undefined // function() {}
		},
		methods: {
			init: function(o) { // 初始化绑定事件
				var me = $(this);
				if (me.is(o.selectors.row)) {
					bindEvent(me, o);
				} else {
					me.find(o.selectors.row).each(function() {
						bindEvent($(this), o);
					});
				}
			},
			calculate: function(o) { // 重新计算小计金额(subtotal)
				var me = $(this);
				if (me.is(o.selectors.row)) {
					doExecCalculate(me, o);
				} else {
					me.find(o.selectors.row).each(function() {
						doExecCalculate($(this), o);
					});
				}
			}
		}
	};
}();
